package com.qiaofang.service.impl;

import com.github.wenhao.jpa.Specifications;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.qiaofang.common.constant.DelFlagEnum;
import com.qiaofang.common.constant.ExceptionEnum;
import com.qiaofang.common.constant.RedisKeyContant;
import com.qiaofang.common.exception.BusinessException;
import com.qiaofang.common.exception.SystemException;
import com.qiaofang.common.model.PageDTO;
import com.qiaofang.common.model.UiListBean;
import com.qiaofang.common.model.UiSelectBean;
import com.qiaofang.common.utils.*;
import com.qiaofang.constant.DepartmentConstant;
import com.qiaofang.constant.PartnerInfoStatusEnum;
import com.qiaofang.constant.PartnerInfoTypeEnum;
import com.qiaofang.dto.DepartmentDTO;
import com.qiaofang.dto.ListPartnerInfoDTO;
import com.qiaofang.dto.PartnerInfoDTO;
import com.qiaofang.entity.PartnerInfo;
import com.qiaofang.repository.PartnerInfoRepository;
import com.qiaofang.service.DepartmentService;
import com.qiaofang.service.PartnerInfoService;
import com.qiaofang.vo.DepartmentVO;
import com.qiaofang.vo.PartnerInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class PartnerInfoServiceImpl implements PartnerInfoService {

    @Autowired
    private PartnerInfoRepository partnerInfoRepository;

    @Autowired
    private DepartmentService departmentService;

    @Override
    public UiListBean<PartnerInfoVO> listPartnerInfo(ListPartnerInfoDTO dto, PageDTO pageDTO) {
        Specification<PartnerInfo> specification = Specifications.<PartnerInfo>and()
                .eq("companyType", dto.getCompanyType())
                .eq(StringUtil.isNotBlank(dto.getStatus()), "status", dto.getStatus())
                .eq(StringUtil.isNotBlank(dto.getAccountType()), "accountType", dto.getAccountType())
                .eq(StringUtil.isNotBlank(dto.getCompanyId()), "higherId", dto.getCompanyId())
                .between(StringUtil.isNotBlank(dto.getCreateTimeStart()), "createTime"
                        , DateUtil.minOfString(dto.getCreateTimeStart()),
                        DateUtil.maxOfString(dto.getCreateTimeEnd()))
                .predicate(StringUtil.isNotBlank(dto.getSearchContent()),
                        Specifications.or()
                                .like("accountName", StringUtil.addLikeParam(dto.getSearchContent()))
                                .like("phone", StringUtil.addLikeParam(dto.getSearchContent()))
                                .build())
                .eq("delFlag", DelFlagEnum.UNDEL.getNo())
                .build();
        Page<PartnerInfo> page = partnerInfoRepository.findAll(specification, PageUtil.getPageByDTO(pageDTO, PageUtil.getCreateTimeDesc()));
        UiListBean<PartnerInfoVO> uiListBean = new UiListBean();
        uiListBean.setList(convertListDomain2VO(page.getContent()));
        uiListBean.setTotalCount(page.getTotalElements());
        return uiListBean;
    }

    @Override
    public List<UiSelectBean> listPartnerInfo(Long type, Long companyId) {
        PartnerInfo example = new PartnerInfo();
        example.setHigherId(String.valueOf(companyId));
        example.setDelFlag(DelFlagEnum.UNDEL.getNo());
        List<PartnerInfo> partnerInfos = partnerInfoRepository.findAll(Example.of(example));
        List<UiSelectBean> list = Lists.newArrayList();
        if (partnerInfos != null) {
            for (PartnerInfo partnerInfo : partnerInfos) {
                UiSelectBean uiSelectBean = new UiSelectBean();
                uiSelectBean.setValue(partnerInfo.getId());
                uiSelectBean.setLabel(partnerInfo.getAccountName());
                list.add(uiSelectBean);
            }
        }
        return list;
    }

    @Override
    public Map<Long, PartnerInfo> listPartnerInfo(List<Long> ids) {
        Map<Long, PartnerInfo> map = Maps.newConcurrentMap();
        if (ids != null && ids.size() > 0) {
            List<PartnerInfo> partnerInfos = partnerInfoRepository.findAllById(ids);
            if (partnerInfos != null) {
                for (PartnerInfo partnerInfo : partnerInfos) {
                    map.put(partnerInfo.getId(), partnerInfo);
                }
            }
        }
        return map;
    }

    private List<PartnerInfoVO> convertListDomain2VO(List<PartnerInfo> partnerInfos) {
        List<PartnerInfoVO> vos = Lists.newArrayList();
        if (partnerInfos != null) {
            for (PartnerInfo partnerInfo : partnerInfos) {
                PartnerInfoVO vo = convertDomain2VO(partnerInfo);
                vos.add(vo);
            }
        }
        return vos;
    }

    private PartnerInfoVO convertDomain2VO(PartnerInfo partnerInfo) {
        if (partnerInfo == null) {
            return null;
        }
        PartnerInfoVO vo = new PartnerInfoVO();
        vo.setId(partnerInfo.getId());
        vo.setAccountName(partnerInfo.getAccountName());
        vo.setTelephone(partnerInfo.getPhone());
        vo.setStatus(partnerInfo.getStatus());
        vo.setCompanyId(partnerInfo.getHigherId());
        vo.setAccountType(partnerInfo.getAccountType());
        vo.setDeptName(partnerInfo.getDeptName());
        vo.setStationedCase(partnerInfo.getStationedCase());
        vo.setCreateTime(partnerInfo.getCreateTime());
        vo.setWxOpenid(partnerInfo.getWxOpenid());
        return vo;
    }

    /**
     * 判断手机号是否存在
     *
     * @param phone
     * @return
     */
    private boolean checkRepeatTelephone(PartnerInfo partnerInfo, String phone) {
        if (partnerInfo != null) {
            if (StringUtil.equals(partnerInfo.getPhone(), phone)) {
                return true;
            }
        }
        PartnerInfo example = new PartnerInfo();
        example.setPhone(phone);
        example.setHigherId(partnerInfo.getHigherId());
        example.setDelFlag(DelFlagEnum.UNDEL.getNo());
        List<PartnerInfo> partnerInfos = partnerInfoRepository.findAll(Example.of(example));
        if (partnerInfos != null && partnerInfos.size() > 0) {
            if (partnerInfos.size() > 1) {
                throw new SystemException(ExceptionEnum.EXIST_MORE_THAN_2_TELEPHONE);
            } else {
                if (partnerInfos.get(0).getId().equals(partnerInfo.getId())) {
                    return true;
                } else {
                    return false;
                }
            }
        } else {
            return true;
        }
    }

    /**
     * 是否存在启用状态下的管理员
     *
     * @return
     */
    private boolean checkExistManager(PartnerInfo partnerInfo) {
        PartnerInfo db = getAdminPartnerInfoByCompanyId(partnerInfo.getHigherId());
        if (db != null) {
            if (db.getId().equals(partnerInfo.getId())) {
                return true;
            } else {
                throw new BusinessException(ExceptionEnum.EXIST_ENABLE_MANAGER);
            }
        } else {
            return true;
        }

    }

    private PartnerInfo getAdminPartnerInfoByCompanyId(String companyId) {
        PartnerInfo example = new PartnerInfo();
        example.setHigherId(companyId);
        example.setAccountType(PartnerInfoTypeEnum.ADMIN.getNo());
        example.setStatus(PartnerInfoStatusEnum.Enable.getNo());
        example.setDelFlag(DelFlagEnum.UNDEL.getNo());
        List<PartnerInfo> list = partnerInfoRepository.findAll(Example.of(example));
        if (list != null && list.size() > 0) {
            if (list.size() > 1) {
                throw new SystemException(ExceptionEnum.EXIST_MORE_THAN_2_ENABLE_MANAGER);
            } else {
                return list.get(0);
            }
        } else {
            return null;
        }
    }

    @Override
    public PartnerInfoVO getAdminPartnerInfoByCompanyId(Long id) {
        PartnerInfo db = getAdminPartnerInfoByCompanyId(String.valueOf(id));
        return convertDomain2VO(db);
    }

    private PartnerInfo savePartnerInfo(PartnerInfoDTO dto) {
        PartnerInfo partnerInfo;
        if (dto.getId() != null) {
            partnerInfo = partnerInfoRepository.findById(dto.getId())
                    .orElseThrow(() -> new BusinessException(ExceptionEnum.NOT_FIND_DB_DATA));
            if (dto.getResetPassword()) {
                partnerInfo.setPassword((PasswordUtil.resetPassword()));
            }
        } else {
            partnerInfo = new PartnerInfo();
            partnerInfo.setPassword((PasswordUtil.resetPassword()));
        }
        partnerInfo.setStatus(PartnerInfoStatusEnum.Enable.getNo());
        partnerInfo.setAccountName(dto.getAccountName());
        partnerInfo.setAccountType(dto.getAccountType());
        partnerInfo.setHigherId(dto.getCompanyId());
        //验证手机号
        if (checkRepeatTelephone(partnerInfo, dto.getTelephone())) {
            partnerInfo.setPhone(dto.getTelephone());
        } else {
            throw new BusinessException(ExceptionEnum.EXIST_TELEPHONE);
        }
        partnerInfo.setDelFlag(DelFlagEnum.UNDEL.getNo());
        //选择公司后,根据公司ID,获取公司下的第一部门(第一部门及公司)
        if(Objects.isNull(dto.getId())){
            DepartmentDTO departmentDTO = new DepartmentDTO();
            departmentDTO.setMerchantId(Long.parseLong(partnerInfo.getHigherId()));
            departmentDTO.setParentId(DepartmentConstant.TOP);
            DepartmentVO department = departmentService.getDepartmentByDTO(departmentDTO);
            if (department != null) {
                partnerInfo.setDeptId(department.getId());
            } else {
                throw new BusinessException(ExceptionEnum.NOT_EXIST_COMPANY);
            }
        }
        partnerInfoRepository.save(partnerInfo);
        return partnerInfo;
    }

    @Override
    public void addPartnerInfo(PartnerInfoDTO partnerInfoDTO) {
        savePartnerInfo(partnerInfoDTO);
    }

    @Override
    public void updatePartnerInfo(PartnerInfoDTO partnerInfoDTO) {
        savePartnerInfo(partnerInfoDTO);
    }

    @Override
    public PartnerInfoVO getPartnerInfo(Long id) {
        PartnerInfo partnerInfo = partnerInfoRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ExceptionEnum.NOT_FIND_DB_DATA));
        return convertDomain2VO(partnerInfo);
    }

    @Override
    public void enablePartnerInfo(Long id) {
        PartnerInfo partnerInfo = partnerInfoRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ExceptionEnum.NOT_FIND_DB_DATA));
        partnerInfo.setStatus(PartnerInfoStatusEnum.Enable.getNo());
        partnerInfoRepository.save(partnerInfo);
    }

    @Override
    public void disablePartnerInfo(Long id) {
        PartnerInfo partnerInfo = partnerInfoRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ExceptionEnum.NOT_FIND_DB_DATA));
        partnerInfo.setStatus(PartnerInfoStatusEnum.Disable.getNo());
        partnerInfoRepository.save(partnerInfo);
    }

    @Override
    public void deletePartnerInfo(Long id) {
        PartnerInfo partnerInfo = partnerInfoRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ExceptionEnum.NOT_FIND_DB_DATA));
        if (StringUtil.equals(partnerInfo.getStatus(), PartnerInfoStatusEnum.Disable.getNo())) {
            partnerInfo.setDelFlag(DelFlagEnum.DEL.getNo());
            partnerInfoRepository.save(partnerInfo);
        } else {
            throw new BusinessException(ExceptionEnum.STATUS_DISABLE_DELETE);
        }
    }

    @Override
    public void installAdminPartnerInfo(Long id) {
        PartnerInfo partnerInfo = partnerInfoRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ExceptionEnum.NOT_FIND_DB_DATA));
        //不限制管理员数量
//        if (checkExistManager(partnerInfo)) {
        partnerInfo.setAccountType(PartnerInfoTypeEnum.ADMIN.getNo());
        partnerInfoRepository.save(partnerInfo);
//        }
    }

    @Override
    public void cancelAdminPartnerInfo(Long id) {
        PartnerInfo partnerInfo = partnerInfoRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ExceptionEnum.NOT_FIND_DB_DATA));
        partnerInfo.setAccountType(PartnerInfoTypeEnum.GENERAL.getNo());
        partnerInfoRepository.save(partnerInfo);
    }

    @Override
    public void batchEnablePartnerInfo(List<Long> ids) {
        List<PartnerInfo> partnerInfos = partnerInfoRepository.findAllById(ids);
        if (partnerInfos != null) {
            for (PartnerInfo partnerInfo : partnerInfos) {
                partnerInfo.setStatus(PartnerInfoStatusEnum.Enable.getNo());
            }
        }
        partnerInfoRepository.saveAll(partnerInfos);
    }

    @Override
    public void batchDisablePartnerInfo(List<Long> ids) {
        List<PartnerInfo> partnerInfos = partnerInfoRepository.findAllById(ids);
        if (partnerInfos != null) {
            for (PartnerInfo partnerInfo : partnerInfos) {
                partnerInfo.setStatus(PartnerInfoStatusEnum.Disable.getNo());
            }
        }
        partnerInfoRepository.saveAll(partnerInfos);
    }

    @Override
    public void batchDeletePartnerInfo(List<Long> ids) {
        List<PartnerInfo> partnerInfos = partnerInfoRepository.findAllById(ids);
        if (partnerInfos != null) {
            for (PartnerInfo partnerInfo : partnerInfos) {
                if (StringUtil.equals(partnerInfo.getStatus(), PartnerInfoStatusEnum.Enable.getNo())) {
                    throw new BusinessException(ExceptionEnum.BATCH_DEL_AGENCY_USER);
                }
                partnerInfo.setDelFlag(DelFlagEnum.DEL.getNo());
            }
        }
        partnerInfoRepository.saveAll(partnerInfos);
    }

    @Override
    public List<PartnerInfo> listPartnerInfoByName(Set<String> residentNameList, List<String> companyIds) {
        return partnerInfoRepository.listPartnerInfoByName(residentNameList, companyIds);
    }

    @Override
    public List<PartnerInfo> listPartnerInfoByPhone(Set<String> phoneList, List<String> companyIds) {
        return partnerInfoRepository.listPartnerInfoByPhone(phoneList, companyIds);
    }

    @Override
    public List<PartnerInfo> selectListByDto(PartnerInfoDTO partnerInfoDTO) {
        Specification<PartnerInfo> specification = Specifications.<PartnerInfo>and()
                .eq(StringUtil.isNotBlank(partnerInfoDTO.getCompanyId()), "higherId", partnerInfoDTO.getCompanyId())
                .eq("delFlag", DelFlagEnum.UNDEL.getNo())
                .build();
        return partnerInfoRepository.findAll(specification);
    }

    @Override
    public void addPartnerInfo(PartnerInfo partnerInfo) {
        partnerInfoRepository.save(partnerInfo);
    }

    @Override
    public void cleanPartnerCache(Long id) {
        PartnerInfo partnerInfo = partnerInfoRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ExceptionEnum.NOT_FIND_DB_DATA));
        if(Objects.nonNull(partnerInfo)){
            List<String> deleteKeys = new ArrayList<>();
            String roleOrgPermissionKey = RedisKeyContant.Permission.DEV_ROLE_ORG_PERMISSION + partnerInfo.getUserRoleId();
            String rolePremisesPermissionKey = RedisKeyContant.Permission.DEV_ROLE_PREMISES_PERMISSION + partnerInfo.getUserRoleId();
            String userOrgPermissionKey = RedisKeyContant.Permission.DEV_USER_ORG_PERMISSION + partnerInfo.getId();
            String userPremisesPermissionKey = RedisKeyContant.Permission.DEV_USER_PREMISES_PERMISSION + partnerInfo.getId();
            deleteKeys.add(roleOrgPermissionKey);
            deleteKeys.add(rolePremisesPermissionKey);
            deleteKeys.add(userOrgPermissionKey);
            deleteKeys.add(userPremisesPermissionKey);
            RedisUtil.delete(deleteKeys);
        }
    }
}
